#include "StdAfx.h"
#include "IPC.h"


ImageProcessing::ImageProcessing()
{
	pHSV = NULL;
	pImage = NULL;
	pImageGray = NULL;
}
ImageProcessing::~ImageProcessing()
{
	pHSV = NULL;
	delete pHSV;
	pImage = NULL;
	delete pImage;
	
}
bool ImageProcessing::LoadImage(char* filename)
{
	pImage = (IplImage*)cvLoadImage(filename);
	if (!pImage)
	{
		nErrorID = 1;
		return false;
	}
	h = pImage->height;
	w = pImage->width;
	byteWidth = pImage->widthStep;

	return true;
}
//H: [0,360]
//S: [0,255]
//V: [0,255]
void ImageProcessing::ConvertRGBtoHSV(unsigned char r, unsigned char g,unsigned char b, HSV &out)
{
	//V=max(R,G,B)
	//S=(V-min(R,G,B))*255/V   ,if V!=0, 
	//  0                      ,otherwise
	//       (G - B)*60/S,  if V=R
	//H= 180+(B - R)*60/S,  if V=G
	//	 240+(R - G)*60/S,  if V=B
	//if H<0 then H=H+360
	unsigned char iMax;
	unsigned char iMin;
	iMax = (r>g)?r:g;
	iMin = (r>g)?g:r;
	iMax = (b>iMax)?b:iMax;
	iMin = (b<iMin)?b:iMin;
	
	//calculate V
	out.V = iMax;

	//calculate S
	if(iMax!=0)
		out.S = (iMax - iMin)*255/iMax;
	else
		out.S = 0;

	//calculate H
	if(out.S==0)
		out.H = 0;// undefine or any
	else
	{
		float fHue;
		float fDelta;
		fDelta = iMax - iMin;
		if(iMax == r)
			fHue = (g-b)/fDelta;
		else if(iMax == g)
			fHue = 2.f + (b-r)/fDelta;
		else
			fHue = 4.f + (r-g)/fDelta;
		fHue*=60;
		if(fHue<0.f)
			fHue += 360.f;
		out.H = (int)fHue;
	}

}

void ImageProcessing::ConvertHSVtoRGB(HSV in, unsigned char &r,unsigned char &g, unsigned char &b)
{
	if(in.S <= 0)
	{
		r = in.V;
		g = in.V;
		b = in.V;
		return;
	}
	else
	{
		float fHue, fSaturation, fValue;
		int i;
		float f;
		float p, q, t;

		if(in.H==360)
			in.H = 0;
		fHue = (float)in.H/60.f;
		i = (int)fHue;
		f = fHue - floor((float)i);

		fValue = (float)in.V/255.f;
		fSaturation = (float)in.S/255.f;

		p = fValue*(1.f	- fSaturation);
		q = fValue*(1.f - (fSaturation*f));
		t = fValue*(1.f - (fSaturation*(1.f - f)));

		switch(i)
		{
			case 0:
				r = (unsigned char)floor(fValue*255+0.5);
				g = (unsigned char)floor(t*255+0.5);
				b = (unsigned char)floor(p*255+0.5);
				break;
			case 1:
				r = (unsigned)floor(q*255+0.5);
				g = (unsigned char)floor(fValue*255+0.5);
				b = (unsigned char)floor(p*255+0.5);
				break;
			case 2:
				r = (unsigned char)floor(p*255+0.5);
				g = (unsigned char)floor(fValue*255+0.5);
				b = (unsigned char)floor(t*255+0.5);
				break;
			case 3:
				r = (unsigned char)floor(p*255+0.5);
				g = (unsigned char)floor(q*255+0.5);
				b = (unsigned char)floor(fValue*255+0.5);
				break;
			case 4:
				r = (unsigned char)floor(t*255+0.5);
				g = (unsigned char)floor(p*255+0.5);
				b = (unsigned char)floor(fValue*255+0.5);
				break;
			case 5:
				r = (unsigned char)floor(fValue*255.f+0.5f);
				g = (unsigned char)floor(p*255.f+0.5f);
				b = (unsigned char)floor(q*255.f+0.5f);
				break;
		}
	}
	//r = ((unsigned char)r>255)?255:r;
	//g = ((unsigned char)g>255)?255:g;
	//b = ((unsigned char)b>255)?255:b;
	//r = ((unsigned char)r<0)?0:r;
	//g = ((unsigned char)g<0)?0:g;
	//b = ((unsigned char)b<0)?0:b;
	return;
}
bool ImageProcessing::RGBtoHSV()
{
	if(!pImage)
		return false;

	pHSV = new HSV[h*w];

	for (int y=0; y<h; y++)
	{
		long int R = y*byteWidth;
		for(int x=0 ; x<w; x++)
		{
			long int idxPixel = R+ x*3;
			unsigned char b = pImage->imageData[idxPixel + 0];
			unsigned char g = pImage->imageData[idxPixel + 1];
			unsigned char r = pImage->imageData[idxPixel + 2];

			long int idx = y*w+x;
			ConvertRGBtoHSV(r,g,b,pHSV[idx]);
			//ConvertHSVtoRGB(pHSV[idx],r,g,b);//test
		}
	}
		
	return true;
};
bool ImageProcessing::HSVtoRGB()
{
	if(!pHSV)
		return false;
	
	for (int y=0; y<h; y++)
	{
		long int R = y*byteWidth;
		for(int x=0 ; x<w; x++)
		{
			long int idxPixel = R+ x*3;
			long int idx = y*w+x;
		
			unsigned char r,g,b;
			ConvertHSVtoRGB(pHSV[idx],r,g,b);

			pImage->imageData[idxPixel + 0] = (char)b;
			pImage->imageData[idxPixel + 1] = (char)g;
			pImage->imageData[idxPixel + 2] = (char)r;
		}
	}
		
	return true;
}
int ImageProcessing::FindChainCode(int x, int y,int &nextX, int &nextY, unsigned char preValue,unsigned char grayValue)
{
	int i,j;
	long int idx;
	int tx, ty;
	unsigned char revIdx;

	i=1;
	j=0;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (0+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
			return 0;
	}

	i=1;
	j=-1;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (7+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
			return 7;
	}

	i=0;
	j=-1;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (6+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
		return 6;
	}

	i=-1;
	j=-1;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (5+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
		return 5;
	}

	i=-1;
	j=0;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (4+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
		return 4;
	}

	i=-1;
	j=1;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (3+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
		return 3;
	}

	i=0;
	j=1;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (2+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
		return 2;
	}

	i=1;
	j=1;
	tx = x+i;
	ty = y-j;
	idx = ty*pImageGray->widthStep + tx;
	if ((unsigned char)pImageGray->imageData[idx]==grayValue)
	{
		nextX = tx;
		nextY = ty;
		revIdx = (1+4)%8;

		if( preValue!=revIdx
			&&preValue!=(revIdx+1)%8
			&&preValue!=(revIdx-1)%8
			)
		return 1;
	}
	return 255;
}
bool ImageProcessing::FilterOnHSV(int Hmin, int Hmax, int Smin, int Smax, int Vmin, int Vmax)
{
	if(!pHSV)
		return false;

	for(int x = 0;x<w;x++)
		for(int y=0;y<h;y++)
		{
			long int idx = y*w+x;
			if(		pHSV[idx].H>=Hmin && pHSV[idx].H<=Hmax
				&&	pHSV[idx].S>=Smin && pHSV[idx].S<=Smax
			)
				pHSV[idx].V = 0;
			else 
				pHSV[idx].V = 255;

			pHSV[idx].H = 0;
			pHSV[idx].S = 0;
		}
	return true;
}
void ImageProcessing::SetupGrayImage(unsigned char opt)
{
	int width;
	int height;
	int depth;
	int channels;

	if(!pImage)
		return;
	if(opt==0)
	{
		width = pImage->width;
		height = pImage->height;
		depth = pImage->depth;
		channels = pImage->nChannels;
	}
	pImageGray = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);
	cvCvtColor(pImage,pImageGray,CV_BGR2GRAY);
}
bool ImageProcessing::MakeCannyEdge()
{
	if(!pImage)
		return false;

	cvCanny(pImageGray,pImageGray,10,100,5);
}
//Chaincode
bool ImageProcessing::CreateChainCode()
{
	if(!pImageGray)
	{
		nErrorID = 51;
		return false;
	}
	ChainCode chain;
	bool bFoundRoot = false;
	bool bFinish =false;
	unsigned char preValue = 0;
	int nRootX, nRootY; //root position.
	int nNextX, nNextY; //next pixel on contour
	nNextX = 0;
	nNextY = 0;
	//find root
	for (int y=0; y<h; y++)
	{
		if(bFoundRoot)
			break;
		long int R = y*pImageGray->widthStep;
		for(int x=0 ; x<w; x++)
		{
			long int idxPixel = R+ x*1;
			unsigned char gray = pImageGray->imageData[idxPixel];
			
			if (gray==255)
			{
				bFoundRoot = true;
				chain.nX = nRootX = x;
				chain.nY = nRootY = y;
				chain.nValue = FindChainCode(x,y,nNextX,nNextY,preValue,255);
				preValue = chain.nValue;
				lChain.push_back(chain);
				break;
			}
		}
	}
	if(!bFoundRoot)
	{
		nErrorID = 52;
		return false;
	}
	//trace contour
	while(nRootX!=nNextX || nRootY!=nNextY)
	{
		int x = nNextX;
		int y = nNextY;
		chain.nX = x;
		chain.nY = y;
		chain.nValue = FindChainCode(x,y,nNextX,nNextY,preValue,255);
		if(chain.nValue==255)
		{
			pImageGray->imageData[y*pImageGray->widthStep+x]=150;
			nErrorID = 53;
			//cout<<"/n[ERROR]: Can not make chain code because the boudary is corrupted.\n";
			return false;
		}
		preValue = chain.nValue;
		lChain.push_back(chain);
		 
		//for checking
		pImageGray->imageData[y*pImageGray->widthStep+x]=100;
	}
	//*/
	/*
	CvMemStorage *storage;
	storage = cvCreateMemStorage(0);

	int numContours = cvFindContours(pImageGray,storage,(CvSeq**)&pChain,sizeof(*pChain),CV_RETR_LIST,CV_CHAIN_CODE);
	Test_PrintChainCode();
	ShowFeaturePoint();
	//*/
	return true;
}
char* ImageProcessing::ErrorReport(int ID)
{
	switch(ID)
	{
	case 1: return "Khong mo duoc file";
		break;
	case 51: return "CreateChainCode(): Anh binary chua khoi tao!";
		break;
	case 52: return "CreateChainCode(): Khong tim thay pixel root!";
		break;
	case 53: return "CreateChainCode(): khong the tao chain code vi duong bien bi gian doan";
		break;
	default: "Khong tim thay loi :)";
		break;
	}
}
bool ImageProcessing::ShowFeaturePoint()
{
	return true;
}
void ImageProcessing::Test_PrintChainCode()
{
	
}
HSV* ImageProcessing::GetHSV()
{
	return pHSV;
}

IplImage* ImageProcessing::GetImageObj()
{
	return pImage;
}
IplImage* ImageProcessing::GetImageGrayObj()
{
	return pImageGray;
}